package com.hqd.ch03.v26.config;

import com.hqd.ch03.v26.beans.PropertyValues;
import org.apache.commons.collections.CollectionUtils;

import java.util.*;
import java.util.stream.Stream;


public class MutablePropertyValues implements PropertyValues {
    private List<PropertyValue> propertyValues = new LinkedList<>();
    private Set<String> processedProperties;

    private volatile boolean converted;

    public List<PropertyValue> getProperties() {
        return propertyValues;
    }

    public void addProperty(String name, Object value) {
        propertyValues.add(new PropertyValue(name, value));
    }

    public void addProperty(PropertyValue propertyValue) {
        propertyValues.add(propertyValue);
    }

    public void add(String name, Object value) {
        this.addProperty(name, value);
    }

    @Override
    public PropertyValue[] getPropertyValues() {
        return this.propertyValues.toArray(new PropertyValue[0]);
    }

    @Override
    public PropertyValue getPropertyValue(String propertyName) {
        for (PropertyValue pv : this.propertyValues) {
            if (pv.getName().equals(propertyName)) {
                return pv;
            }
        }
        return null;
    }

    @Override
    public PropertyValues changesSince(PropertyValues old) {
        MutablePropertyValues changes = new MutablePropertyValues();
        if (old == this) {
            return changes;
        }

        for (PropertyValue newPv : this.propertyValues) {
            PropertyValue pvOld = old.getPropertyValue(newPv.getName());
            if (pvOld == null || !pvOld.equals(newPv)) {
                changes.addProperty(newPv);
            }
        }
        return changes;
    }

    @Override
    public boolean contains(String propertyName) {
        return (getPropertyValue(propertyName) != null ||
                (this.processedProperties != null && this.processedProperties.contains(propertyName)));
    }

    @Override
    public boolean isEmpty() {
        return CollectionUtils.isEmpty(propertyValues);
    }

    public void registerProcessedProperty(String propertyName) {
        if (this.processedProperties == null) {
            this.processedProperties = new HashSet<>(4);
        }
        this.processedProperties.add(propertyName);
    }

    public void clearProcessedProperty(String propertyName) {
        if (this.processedProperties != null) {
            this.processedProperties.remove(propertyName);
        }
    }

    public void setConverted() {
        this.converted = true;
    }

    public boolean isConverted() {
        return this.converted;
    }

    @Override
    public Iterator<PropertyValue> iterator() {
        return Collections.unmodifiableList(this.propertyValues).iterator();
    }

    @Override
    public Spliterator<PropertyValue> spliterator() {
        return Spliterators.spliterator(this.propertyValues, 0);
    }

    @Override
    public Stream<PropertyValue> stream() {
        return this.propertyValues.stream();
    }

    public List<PropertyValue> getPropertyValueList() {
        return this.propertyValues;
    }
}
